/* The implementation of class Object for Objective-C.
   Copyright (C) 1993, 1994, 1995, 1997, 2002, 2009 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.

GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <objc/Protocol.h>
#include <objc/runtime.h>
#include <ofc/DObject.h>


@implementation DObject

+ (id) initialize
{
  return self;
}

+ (id) alloc
{
  return class_createInstance(self, 0);
}

- (id) init
{
  return self;
}

+ (id) new
{
  return [[self alloc] init];
}

- (id) free
{
  return object_dispose(self);
}

- (id) copy
{
  return [[self shallowCopy] deepen];
}

- (id) shallowCopy
{
  return object_copy(self, 0);
}

- (id) deepen
{
  return self;
}

- (id) deepCopy
{
  return [self copy];
}

- (Class)class
{
  return object_getClass(self);
}

+ (Class)class
{
  return self;
}


- (Class)superClass
{
  return class_getSuperclass(object_getClass(self));
}

+ (Class)superClass
{
  return class_getSuperclass(self);
}

- (Class)metaClass
{
  return objc_getMetaClass(object_getClassName(self));
}

- (const char *)name
{
  return object_getClassName(self);
}

+ (const char *)name
{
  return class_getName(self);
}

- (id) self
{
  return self;
}

- (unsigned int)hash
{
  return (size_t)self;
}

- (BOOL)isEqual:anObject
{
  return self==anObject;
}

- (int)compare:(id)anotherObject;
{
  if ([self isEqual:anotherObject])
  {
    return 0;
   }
  // Ordering objects by their address is pretty useless, 
  // so subclasses should override this in some useful way.
  else if ((id)self > anotherObject)
  {
    return 1;
  }
  else
  {
    return -1;
  }
}

- (BOOL)isMetaClass
{
  return NO;
}

- (BOOL)isClass
{
  return NO;
}

+ (BOOL)isClass
{
  return YES;
}


- (BOOL)isInstance
{
  return NO;
}

- (BOOL)isKindOf:(Class)aClassObject
{
  Class class;

  for (class = self->isa; class!=Nil; class = class_getSuperclass(class))
  {
    if (class==aClassObject)
    {
      return YES;
    }
  }
  return NO;
}

- (BOOL)isMemberOf:(Class)aClassObject
{
  return self->isa==aClassObject;
}

- (BOOL)isKindOfClassNamed:(const char *)aClassName
{
  Class class;

  if (aClassName!=NULL)
    for (class = self->isa; class!=Nil; class = class_getSuperclass(class))
      if (!strcmp(class_getName(class), aClassName))
        return YES;
  return NO;
}

- (BOOL)isMemberOfClassNamed:(const char *)aClassName
{
  return ((aClassName!=NULL)
          &&!strcmp(class_getName(self->isa), aClassName));
}

+ (BOOL)instancesRespondTo:(SEL)aSel
{
  return class_getInstanceMethod(self, aSel) != (Method)0;
}

- (BOOL)respondsTo:(SEL)aSel
{
  if (class_getInstanceMethod(self->isa, aSel) != NULL)
  {
    return YES;
  }
  else if (class_getClassMethod(self->isa, aSel) != NULL)
  {
    return YES;
  }
  else
  {
    return NO;
  }
}

+ (IMP)instanceMethodFor:(SEL)aSel
{
  return method_getImplementation(class_getInstanceMethod(self, aSel));
}

+ (BOOL) conformsTo: (Protocol*)aProtocol
{
  if (!class_conformsToProtocol(self, aProtocol))
  {
    id parent;

    if ((parent = [self superClass]))
      return [parent conformsTo: aProtocol];
    else
      return NO;
  }
  else
    return YES;
}

- (BOOL) conformsTo: (Protocol*)aProtocol
{
  return [[self class] conformsTo:aProtocol];
}

- (IMP)methodFor:(SEL)aSel
{
  Method method;
  
  if ((method = class_getInstanceMethod(self->isa, aSel)) != NULL)
  {
    return method_getImplementation(method);
  }
  else if ((method = class_getClassMethod(self->isa, aSel)) != NULL)
  {
    return method_getImplementation(method);
  }
  else
  {
    return NULL;
  }
}

+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
{
  return ((struct objc_method_description *) class_getInstanceMethod(self, aSel));
}

- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
{
  Method method;
  
  if ((method = class_getInstanceMethod(self->isa, aSel)) != NULL)
  {
    return (struct objc_method_description *)(method);
  }
  else if ((method = class_getClassMethod(self->isa, aSel)) != NULL)
  {
    return (struct objc_method_description *)(method);
  }
  else
  {
    return NULL;
  }
}

- (id) perform:(SEL)aSel
{
  Method method = class_getInstanceMethod(self->isa, aSel);
  
  if (method == NULL)
  {
    return [self error:"invalid selector passed to %s", sel_getName(_cmd)];
  }
  
  IMP msg = method_getImplementation(method);
  
  return (*msg)(self, aSel);
}

- (id) perform:(SEL)aSel with:anObject
{
  Method method = class_getInstanceMethod(self->isa, aSel);
  
  if (method == NULL)
  {
    return [self error:"invalid selector passed to %s", sel_getName(_cmd)];
  }
  
  IMP msg = method_getImplementation(method);
  
  return (*msg)(self, aSel, anObject);
}

- (id) perform:(SEL)aSel with:anObject1 with:anObject2
{
  Method method = class_getInstanceMethod(self->isa, aSel);
  
  if (method == NULL)
  {
    return [self error:"invalid selector passed to %s", sel_getName(_cmd)];
  }
  
  IMP msg = method_getImplementation(method);
  
  return (*msg)(self, aSel, anObject1, anObject2);
}

#if 0
- (id)forward:(SEL)aSel :...
{
  return (retval_t)[self doesNotRecognize: aSel];
}

- (id)performv:(SEL)aSel :...
{
  return objc_msg_sendv(self, aSel, ...);
}


+ (id) poseAs:(Class)aClassObject
{
  return class_pose_as(self, aClassObject);
}

- (Class)transmuteClassTo:(Class)aClassObject
{
  if (object_is_instance(self))
    if (class_is_class(aClassObject))
      if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
        if ([self isKindOf:aClassObject])
          {
            Class old_isa = isa;
            isa = aClassObject;
            return old_isa;
          }
  return nil;
}
#endif

- (id) subclassResponsibility:(SEL)aSel
{
  return [self error:"subclass should override %s", sel_getName(aSel)];
}

- (id) notImplemented:(SEL)aSel
{
  return [self error:"method %s not implemented", sel_getName(aSel)];
}

- (id) shouldNotImplement:(SEL)aSel
{
  return [self error:"%s should not implement %s", 
	             object_getClassName(self), sel_getName(aSel)];
}

- (id) doesNotRecognize:(SEL)aSel
{
  return [self error:"%s does not recognize %s",
                     object_getClassName(self), sel_getName(aSel)];
}

- (id) error:(const char *)aString, ...
{
  const char FMT[] = "error: %s\n%s\n";
  
  char fmt[(strlen(FMT)+strlen((char*)object_getClassName(self))
            +((aString!=NULL)?strlen((char*)aString):0)+8)];
  va_list ap;

  sprintf(fmt, FMT, object_getClassName(self),
                    (aString!=NULL)?aString:"");

  va_start(ap, aString);
  //objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap);
  va_end(ap);
  return nil;
}

+ (int)version
{
  return class_getVersion(self);
}

+ (id) setVersion:(int)aVersion
{
  class_setVersion(self, aVersion);
  return self;
}
@end
